#include "gen.h"
#include "errors.h"

Py_ssize_t gen_len_gen(GEN val) {
	if(typ(val)==t_LIST) return lgeflist(val);
	if(typ(val)==t_POL || typ(val)==t_PADIC || typ(val) == t_SER || typ(val)==t_INT || 
		typ(val)==t_REAL) return lg(val)-2;
	return lg(val) - 1;
}

static Py_ssize_t 
gen_len(PyObject* _obj) {
	PyGEN* obj = (PyGEN*) _obj;
	return gen_len_gen(obj->val);
}

GEN gen_item_gen(GEN val, Py_ssize_t n) {
	if(typ(val)==t_INT || typ(val)==t_STR || typ(val)==t_REAL || typ(val)==t_VECSMALL) {
		PyErr_SetString(pari_error, "simple type in get item");
		return NULL;
	}
	Py_ssize_t size = gen_len_gen(val);
	int shift = lg(val)-size;
	if(n<0 || n>=size) {
		PyErr_SetString(PyExc_IndexError, "index is out of range in get item");
		return NULL;
	}
	return gel(val, shift+n);
}

static PyObject*
gen_item(PyObject* _obj, Py_ssize_t n) {
	return (PyObject*) create_gen(gen_item_gen(((PyGEN*) _obj)->val, n));
}

long get_long_arg(PyObject* args, int* args_used, bool has_def, long def, bool* error);

static int
gen_ass_item(PyObject* _obj, Py_ssize_t n, PyObject* _item) {
	PyGEN* obj = (PyGEN*) _obj;
	GEN val = obj->val;
	//if(typ(val)==t_INT || typ(val)==t_STR || typ(val)==t_REAL || typ(val)==t_VECSMALL) {
	// other types can be spoiled by changing an element
	if(typ(val)!=t_VEC && typ(val)!=t_COL  && typ(val)!=t_LIST) {
		PyErr_SetString(pari_error, "set item is only for t_VEC, t_COL and t_LIST");
		return -1;
	}
	Py_ssize_t size = gen_len(_obj);
	int shift = lg(val)-size;
	if(n<0 || n>=size) {
		PyErr_SetString(pari_error, "index is out of range in set item");
		return -1;
	}
	pari_sp __av = avma;	
	GEN item = gen_cast(_item);
	if(item == NULL) {
		avma = __av;
		return -1;
	}
	CATCH_PARI {
		SET_ERROR;
		avma = __av;
		return -1;
	} TRY_PARI {
		GEN oldval = (GEN)(val[shift+n]);
		gel(val, shift+n) = item;
		GEN newval = gclone(val);
		gel(val, shift+n) = oldval;
		gunclone(val);
		obj->val = newval;
		avma = __av;
		return 0;
	} ENDCATCH_PARI
}

PySequenceMethods gen_as_sequence = {
	gen_len, // lenfunc sq_length;
	0, // binaryfunc sq_concat;
	0, // ssizeargfunc sq_repeat;
	gen_item, // ssizeargfunc sq_item;
	0, // ssizessizeargfunc sq_slice;
	gen_ass_item, // ssizeobjargproc sq_ass_item;
	0, // ssizessizeobjargproc sq_ass_slice;
	0, // objobjproc sq_contains;
	    /* Added in release 2.0 */
	0, // binaryfunc sq_inplace_concat;
	0  // ssizeargfunc sq_inplace_repeat;
};

